#pragma once

#include "SFML/Graphics.hpp"
#include "GameGlobals.h"
#include "Utility.h"

class BaseEntity;

typedef void (*InputFunc)(BaseEntity* ent);

class BaseEntity
{
private:
	float fNextThink;
	float fLastThink;	
	sf::Vector2f Position;
	sf::Vector2f Origin;
	
	sf::Matrix3 Matrix;
	bool MatrixNeedsUpdate;

	float Health;
	float MaxHealth;

	bool bAlive;
	friend class EntityManager;
protected:
	sf::RenderWindow *pRender;
	std::map<std::string, InputFunc> Inputs;
	std::map<std::string, int> MetaData;
	float Angle;
	bool PhysicsEnabled;
	std::string ClassName;
	BaseEntity* mOwner;
public:
	void SetAlive(bool a) {bAlive = a;};
	bool GetAlive() {return bAlive;};

	void Fire(std::string &Name);
	void RegisterInput(std::string &Name, InputFunc Func);

	std::string GetClass() {return ClassName;};

	sf::Matrix3 GetMatrix();
	int ID;
	int DrawOrder;
	bool DeleteMe;
	BaseEntity(sf::RenderWindow *App);
	~BaseEntity(void);
	void Delete();
	void Delete(bool Callback);
	int GetMeta(std::string ID);
	int SetMeta(std::string ID, int Value);

	bool GetPhysicsEnabled() {return PhysicsEnabled;};

	sf::Vector2f ToGlobal(sf::Vector2f &point);
	sf::Vector2f ToLocal(sf::Vector2f &point);

	void SetOwner(BaseEntity* o) {mOwner = o;};
	BaseEntity* GetOwner() {return mOwner;};

	virtual void Tick();
	virtual void Think() = 0;
	virtual void Draw() = 0;
	virtual void OnDelete() {}; //Called before the entity is deleted
	virtual void OnTakeDamage(BaseEntity* inf, float Amount) {};

	std::string GetClassName() {return ClassName;};

	sf::Vector2f GameCoordsToSFML(sf::Vector2f Pos);
	sf::Vector2f SFMLToGameCoords(sf::Vector2f Pos);

	sf::Vector2f GetSFMLPos() {return GameCoordsToSFML(GetPos());};

	void SetMaxHealth(float H) {MaxHealth = H;};
	float GetMaxHealth() {return MaxHealth;};

	void SetHealth(float H) {Health = H;};
	float GetHealth() {return Health;};
	void AddHealth(float am) {Health += am; if (Health > MaxHealth) Health = MaxHealth;};

	void SetPos(sf::Vector2f Pos) { Position = Pos; MatrixNeedsUpdate = true;};
	void SetPos(float x, float y) { Position.x = x; Position.y = y; MatrixNeedsUpdate = true;};
	sf::Vector2f GetPos() { return Position;};

	void SetOrigin(sf::Vector2f Or) {Origin = Or; MatrixNeedsUpdate = true;};
	sf::Vector2f GetOrigin() {return Origin;};

	void SetAngle(float ang) {Angle = Util::NormalizeAngle(ang); MatrixNeedsUpdate = true;};
	float GetAngle() {return Angle;};

	void NextThink(float time) {fNextThink = time;};
	float GetNextThink() {return fNextThink;};
};

template<class T>
struct RegisterClass
{
	RegisterClass(char* name)
	{
		BaseFactory* F = new EntityFactory<T>;
		EntityManager::Instance()->RegisterEntity(std::string(name), F);
	}
};

#define LINKCLASSTONAME(name, t) \
	static RegisterClass<t> Regi(name);
